﻿using HalconDotNet;
using NeuroCheck.PlugInLib.API;
using NeuroCheck.PlugInLib.Base;
using NeuroCheck.PlugInLib.ImageProcessing;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace CLVisionHalconNC620.Transform
{
    public class ImageTransform
    {
        public static Bitmap Himage2Bitmap(HImage halconOutImage, out int ErrorCode, out string ErrorText)
        {
            HTuple imageChannel;
            Bitmap nCBitmap = null;
            ErrorCode = 0;
            ErrorText = "";

            //图像通道数
            imageChannel = halconOutImage.CountChannels();
            if (imageChannel == null || imageChannel.Length == 0)
            {
                ErrorCode = -1;
                ErrorText = "图像格式有误！";
                return nCBitmap;
            }
            HTuple type, width, height;

            //图像尺寸
            halconOutImage.GetImageSize(out width, out height);

            PixelFormat imagePixelFormat;

            if (imageChannel == 3)
            {
                /*
                //RGB图像
                imagePixelFormat = PixelFormat.Format24bppRgb;
                */

                imagePixelFormat = PixelFormat.Format32bppRgb;
            }
            else
            {
                imagePixelFormat = PixelFormat.Format8bppIndexed;
            }

            nCBitmap = new Bitmap(width, height, imagePixelFormat);
            Rectangle rect = new Rectangle(0, 0, width, height);

            BitmapData bitmapData = nCBitmap.LockBits(rect, ImageLockMode.ReadWrite, imagePixelFormat);
            int imageLength = width * height;
            IntPtr intPtr = bitmapData.Scan0;

            if (imageChannel == 3)
            {
                /*  该方法扣出来的图像倾斜
                //RGB图像
                IntPtr pGreen = new IntPtr();
                IntPtr pRed = new IntPtr();
                IntPtr pBlue = new IntPtr();
                string newType;
                int newWidth, newHeight;
                halconOutImage.GetImagePointer3(out pRed, out pGreen, out pBlue, out newType, out newWidth, out newHeight);
                byte[] ImageDataR = new byte[imageLength];
                byte[] ImageDataG = new byte[imageLength];
                byte[] ImageDataB = new byte[imageLength];

                Marshal.Copy(pRed, ImageDataR, 0, imageLength);
                Marshal.Copy(pGreen, ImageDataG, 0, imageLength);
                Marshal.Copy(pBlue, ImageDataB, 0, imageLength);
                byte[] buffer = new byte[imageLength * (imageChannel)];

                for (int i = 0; i < imageLength; i++)
                {
                    buffer[3 * i] = ImageDataB[i];
                    buffer[3 * i + 1] = ImageDataG[i];
                    buffer[3 * i + 2] = ImageDataG[i];
                }
                Marshal.Copy(buffer, 0, intPtr, imageLength * imageChannel);
                nCBitmap.UnlockBits(bitmapData);
                */

                ///*解决图像倾斜，可用
                //获取存放R\G\B值的指针
                halconOutImage.GetImagePointer3(out IntPtr r, out IntPtr g, out IntPtr b, out string ttype, out int w, out int h);
                byte[] red = new byte[w * h];
                byte[] green = new byte[w * h];
                byte[] blue = new byte[w * h];
                //将指针指向地址的值取出来放到byte数组中
                Marshal.Copy(r, red, 0, w * h);
                Marshal.Copy(g, green, 0, w * h);
                Marshal.Copy(b, blue, 0, w * h);
                unsafe
                {
                    byte* bptr2 = (byte*)bitmapData.Scan0;
                    for (int i = 0; i < w * h; i++)
                    {
                        bptr2[i * 4] = blue[i];
                        bptr2[i * 4 + 1] = green[i];
                        bptr2[i * 4 + 2] = red[i];
                        bptr2[i * 4 + 3] = 255;
                    }
                }
                nCBitmap.UnlockBits(bitmapData);

                //将32位图像转换为24位
                //Bitmap bitmap24 = new Bitmap(nCBitmap.Width, nCBitmap.Height, PixelFormat.Format24bppRgb);
                //Graphics graphics = Graphics.FromImage(bitmap24);
                //graphics.DrawImage(nCBitmap, new Rectangle(0, 0, nCBitmap.Width, nCBitmap.Height));


                return nCBitmap;
                // */

                /* Halcon方法创建交错图像，
                 * 该方法转换彩色图像正常，转换黑白图像有问题，且bitmap转NC图像时图像黑图
                HOperatorSet.GetImageSize(halconOutImage, out width0, out height0);
                HOperatorSet.InterleaveChannels(halconOutImage, out HObject InterImage, "rgb", 4 * width0, 0);
                HOperatorSet.GetImagePointer1(InterImage, out HTuple Pointer, out type, out width, out height);
                IntPtr ptr = Pointer;
                Bitmap res24 = new Bitmap(width / 4, height, width, PixelFormat.Format24bppRgb, ptr);

                //Form form = new Form();
                //PictureBox pictureBox = new PictureBox();
                //pictureBox.Image = res24;
                //pictureBox.SizeMode = PictureBoxSizeMode.Zoom;
                //pictureBox.Dock = DockStyle.Fill;
                //form.Controls.Add(pictureBox);
                //form.Show();
                */

            }
            else
            {
                //================================黑图
                ////halconOutImage.GetImagePointer1(out IntPtr r, out IntPtr g, out IntPtr b, out string ttype, out int w, out int h);
                //IntPtr pData = halconOutImage.GetImagePointer1(out HTuple t1, out HTuple w1, out HTuple h1);
                //Bitmap curBitmap = new Bitmap(w1.I, h1.I, PixelFormat.Format8bppIndexed);
                //ColorPalette pal = curBitmap.Palette;
                ////for (int i = 0; i < 255; i++)
                ////{
                ////    pal.Entries[i] = Color.FromArgb(255, i, i, i);
                ////}
                //curBitmap.Palette = pal;
                //BitmapData bitmapData1 = curBitmap.LockBits(new Rectangle(0, 0, w1, h1), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
                //int pixelsize = Bitmap.GetPixelFormatSize(bitmapData1.PixelFormat) / 8;
                //int stride = bitmapData1.Stride;
                ////int ptr = bitmapData1.Scan0.ToInt32();
                ///  nCBitmap.UnlockBits(bitmapData1);

                ////黑白图像----图像有问题
                //IntPtr pData = halconOutImage.GetImagePointer1(out type, out width, out height);
                //int pixelSize = Bitmap.GetPixelFormatSize(bitmapData.PixelFormat) / 8;
                //byte[] buffer = new byte[imageLength];
                //Marshal.Copy(pData, buffer, 0, buffer.Length);
                //unsafe
                //{
                //    fixed (byte* bytePointer = buffer)
                //    {
                //        ColorPalette pal = nCBitmap.Palette;
                //        for (int i = 0; i <= byte.MaxValue; i++)
                //        {
                //            pal.Entries[i] = Color.FromArgb(byte.MaxValue, i, i, i);
                //        }
                //        nCBitmap.Palette = pal;
                //    }
                //    Marshal.Copy(buffer, 0, intPtr, imageLength);
                //}
                //  nCBitmap.UnlockBits(bitmapData);


                //==============测试可以用

                HTuple hpoint;
                HObject image = new HObject(halconOutImage);
                HOperatorSet.GetImagePointer1(image, out hpoint, out type, out width, out height);
                int bytes = width * height;
                byte[] rgbvalues = new byte[bytes];
                Marshal.Copy(hpoint, rgbvalues, 0, bytes);
                nCBitmap= CreateBitmap(rgbvalues, width, height);
              
            }
            return nCBitmap;
        }

        //public static Bitmap Himage2Bitmap(HImage image)
        //{
        //    HOperatorSet.CountChannels(image, out HTuple channels);
        //    if (channels == 1)
        //    {
        //        HTuple hpoint, type, width, height;
        //        const int Alpha = 255;
        //        HOperatorSet.GetImagePointer1(image, out hpoint, out type, out width, out height);
        //        var res = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
        //        ColorPalette pal = res.Palette;
        //        for (int i = 0; i <= 255; i++)
        //        {
        //            pal.Entries[i] = Color.FromArgb(Alpha, i, i, i);
        //        }
        //        res.Palette = pal;
        //        Rectangle rect = new Rectangle(0, 0, width, height);
        //        BitmapData bitmapData = res.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
        //        int PixelSize = Bitmap.GetPixelFormatSize(bitmapData.PixelFormat) / 8;
        //        IntPtr ptr1 = bitmapData.Scan0;
        //        IntPtr ptr2 = hpoint;
        //        byte[] rgbvalues = new byte[width * height];
        //        Marshal.Copy(ptr2, rgbvalues, 0, rgbvalues.Length);
        //        if (width % 4 == 0)
        //        {
        //            Marshal.Copy(rgbvalues, 0, ptr1, rgbvalues.Length);
        //        }
        //        else
        //        {
        //            int stride = bitmapData.Stride;
        //            Parallel.For(0, height, r =>
        //            {
        //                Marshal.Copy(rgbvalues, r * width, IntPtr.Add(ptr1, r * stride), width);
        //            });
        //        }

        //        res.UnlockBits(bitmapData);

        //        return res;
        //    }
        //    else if (channels == 3)
        //    {
        //        HTuple width0, height0;
        //        //获取图像尺寸
        //        HOperatorSet.GetImageSize(image, out width0, out height0);
        //        //创建交错格式图像
        //        HOperatorSet.InterleaveChannels(image, out HObject InterImage, "rgb", 4 * width0, 0);
        //        //获取交错格式图像指针
        //        HTuple type, width, height;
        //        HOperatorSet.GetImagePointer1(InterImage, out HTuple Pointer, out type, out width, out height);
        //        IntPtr ptr = Pointer;
        //        //构建新Bitmap图像
        //        var res24 = new Bitmap(width / 4, height, width, PixelFormat.Format24bppRgb, ptr);
        //        return res24;


        //    }
        //    else
        //        return null;
        //}

        public static NcPIImage Himage2NcImage(HImage halconOutImage, out int ErrorCode, out string ErrorText)
        {
            NcPIImage ncPIImage = null;
            ErrorCode = 0;
            ErrorText = "";
            Bitmap tempImage = Himage2Bitmap(halconOutImage, out int code, out string text);
            if (code == -1)
            {
                ErrorCode = code;
                ErrorText = text;
                return ncPIImage;
            }

         
            ncPIImage = new NcPIImage(tempImage);
            return ncPIImage;

        }

        public static HObject NcImage2Hobject(NcPIImage nCImage)
        {
            int width = nCImage.Width;
            int height = nCImage.Height;
            int countChannels = nCImage.CountOfChannels;
            int totalLength = width * height * countChannels;
            PixelFormat imagePixelFormat;
            if (countChannels == 3)
            {
                imagePixelFormat = PixelFormat.Format32bppArgb;
            }
            else
            {
                imagePixelFormat = PixelFormat.Format8bppIndexed;
            }
            Bitmap curBitmap = new Bitmap(nCImage.Width, nCImage.Height, imagePixelFormat);
            Rectangle rect = new Rectangle(0, 0, nCImage.Width, nCImage.Height);
            HObject HalconImage;

            //RGB
            if (countChannels == 3)
            {
                byte[] imageDataR = new byte[width * height];
                byte[] imageDataG = new byte[width * height];
                byte[] imageDataB = new byte[width * height];
                imageDataR = (byte[])nCImage.GetChannelData(0);
                imageDataG = (byte[])nCImage.GetChannelData(1);
                imageDataB = (byte[])nCImage.GetChannelData(2);

                BitmapData bitmapData = curBitmap.LockBits(rect, ImageLockMode.ReadWrite, imagePixelFormat);
                IntPtr ptrR = bitmapData.Scan0;
                byte[] valueR = new byte[width * height];
                byte[] valueG = new byte[width * height];
                byte[] valueB = new byte[width * height];
                for (int i = 0; i < width * height; i++)
                {
                    valueR[i] = imageDataR[i];
                    valueG[i] = imageDataG[i];
                    valueB[i] = imageDataB[i];
                }
                unsafe
                {
                    fixed (byte* pR = valueR, pG = valueG, pB = valueB)
                    {
                        HOperatorSet.GenImage3(out HalconImage, "byte", width, height, new IntPtr(pR), new IntPtr(pG), new IntPtr(pB));
                    }
                }
                curBitmap.UnlockBits(bitmapData);
            }
            //黑白
            else
            {
                BitmapData bmpdata = curBitmap.LockBits(rect, ImageLockMode.ReadWrite, imagePixelFormat);
                IntPtr ptr = bmpdata.Scan0;
                byte[] rgbvalues = new byte[totalLength];
                Marshal.Copy(ptr, rgbvalues, 0, totalLength);
                byte[] imageData = new byte[width * height];
                imageData = (byte[])nCImage.GetChannelData(0);
                for (int i = 0; i < totalLength; i++)
                {
                    rgbvalues[i] = imageData[i];
                }
                Marshal.Copy(rgbvalues, 0, ptr, totalLength);
                HOperatorSet.GenImage1(out HalconImage, "byte", width, height, ptr);
                curBitmap.UnlockBits(bmpdata);
            }
            return HalconImage;
        }


        public static Bitmap CreateBitmap(byte[] originalImagdata, int originalWidth, int originalHeight)
        {
            Bitmap resultBitmap = new Bitmap(originalWidth, originalHeight, PixelFormat.Format8bppIndexed);
            //将位图存入内存
            MemoryStream curImageStream = new MemoryStream();
            resultBitmap.Save(curImageStream, ImageFormat.Bmp);
            curImageStream.Flush();
            //位图需要DWord对齐，计算需要补位的个数
            int curPadNum = ((originalWidth * 8 + 31) / 32 * 4) - originalWidth;
            //最终生成位图的数据大小
            int bitmapDataSize = ((originalWidth * 8 + 31) / 32 * 4) * originalHeight;
            //数据部分相对文件开始偏移，具体参考位图文件格式
            int dataOffset = ReadData(curImageStream, 10, 4);
            //改变调色板，默认的调色板是32位彩色的，需要改为256色的调色板
            int paletteStart = 54;
            int paletteEnd = dataOffset;
            int color = 0;
            for (int i = paletteStart; i < paletteEnd; i += 4)
            {
                byte[] tempcolor = new byte[4];
                tempcolor[0] = (byte)color;
                tempcolor[1] = (byte)color;
                tempcolor[2] = (byte)color;
                tempcolor[3] = (byte)0;
                color++;
                curImageStream.Position = i;
                curImageStream.Write(tempcolor, 0, 4);
            }
            //最终生成的位图数据、大小、高度没有变，宽度需要调整
            byte[] destImageData = new byte[bitmapDataSize];
            int destWidth = originalWidth + curPadNum;
            //生成最终的位图数据 ，注意的是，位图数据从左到右，从下到上，所有需要颠倒
            for (int originalRowIndex = originalHeight - 1; originalRowIndex >= 0; originalRowIndex--)
            {
                int destRowIndex = originalHeight - originalRowIndex - 1;
                for (int dataIndex = 0; dataIndex < originalWidth; dataIndex++)
                {
                    //同时需要注意，新的位图数据的宽度已经变化，destWidth，否则或产生错位
                    destImageData[destRowIndex * destWidth + dataIndex] = originalImagdata[originalRowIndex * originalWidth + dataIndex];
                }
            }
            ///将流的position移到数据段
            curImageStream.Position = dataOffset;
            //将新位图数据写入内存
            curImageStream.Write(destImageData, 0, bitmapDataSize);
            curImageStream.Flush();
            //将内存中的位图写入bitmap对象
            resultBitmap = new Bitmap(curImageStream);
            return resultBitmap;
        }
        private static int ReadData(MemoryStream curStream, int statPosition, int length)
        {
            int result = -1;
            byte[] tempData = new byte[length];
            curStream.Position = statPosition;
            curStream.Read(tempData, 0, length);
            result = BitConverter.ToInt32(tempData, 0);
            return result;
        }
    }
}
